<?php
namespace App\Http\Logic;

use App\Models\SwtChains;
use App\Models\SwtMarketChains;
use App\Models\SwtNetwork;
use App\Models\SwtNetworkChain;
use App\Models\SwtOrder;
use App\Models\SwtTradeAccount;
use App\Models\SwtTradeAddress;
use App\Models\SwtTradeOrder;
use App\Services\WebThreeService;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class TickersLogic extends BaseLogic
{
    /**
     * @notes 更新链信息，并返回更新的数量
     * @return false|int
     * @author Evil丿
     * @date 2025/04/14 14:06
     */
    public static function updateChains()
    {
        $res = WebThreeService::getSupportedChains();

        if($res['code'] != 0) {
            self::$error = $res['msg'];
            return false;
        }

        $chain_list = $res['data'];

        $num = 0;

        $model = new SwtChains();

        foreach($chain_list as $v) {
            $res = $model -> updateOrCreate(
                [
                    'chain_index' => $v['chainIndex'],
                ],
                [
                    "name"       => $v['name'],
                    "logo_url"   => $v['logoUrl'],
                    "short_name" => $v['shortName']
                ]
            );

            if($res) {
                $num ++ ;
            }
        }

        return $num;
    }

    /**
     * @notes 更新行情数据
     * @param $instType
     * @return false|int
     * @author Evil丿
     * @date 2025/04/15 13:30
     */
    public static function updateMarkers($instType)
    {
        $res = WebThreeService::getInstruments($instType);

        if($res['code'] != 0) {
            self::$error = $res['msg'];
            return false;
        }

        $marker_list = $res['data'];

        $num = 0;

        $model = new SwtMarketChains();

        foreach($marker_list as $v) {
            $milliseconds = Carbon::createFromTimestampMs($v['listTime']);

            $res = $model -> updateOrCreate(
                [
                    'inst_id'   => $v['instId'],
                    "inst_type" => $v['instType'],
                ],
                [
                    "base_ccy"  => $v['baseCcy'],
                    "quote_ccy" => $v['quoteCcy'],
                    "lever"     => $v['lever'],
                    "state"     => $v['state'],
                    "list_time" => $milliseconds -> format('Y-m-d H:i:s'),
                ]
            );

            if($res) {
                $num ++ ;
            }
        }

        return $num;
    }

    /**
     * @notes 缓存行情数据
     * @param string $instType
     * @param int    $ttl
     * @return bool
     * @author Evil丿
     * @date 2025/04/14 17:15
     */
    public static function cacheMarketTickers(string $instType) : bool
    {
        $res = WebThreeService::getMarketTickers($instType);

        if($res['code'] != 0) {
            self::$error = $res['msg'];
            return false;
        }

        $usdt = [];

        foreach($res['data'] as $v) {
            if($v['instId'] == "USDT-USD") {
                $usdt = $v;
            }

            SwtMarketChains::where("inst_id", $v['instId']) -> update([
                "last"      => $v['last'],
                "lastSz"    => $v['lastSz'],
                "askPx"     => $v['askPx'],
                "askSz"     => $v['askSz'],
                "bidPx"     => $v['bidPx'],
                "bidSz"     => $v['bidSz'],
                "open24h"   => $v['open24h'],
                "high24h"   => $v['high24h'],
                "low24h"    => $v['low24h'],
                "volCcy24h" => $v['volCcy24h'],
                "vol24h"    => $v['vol24h'],
                "sodUtc0"   => $v['sodUtc0'],
                "sodUtc8"   => $v['sodUtc8']
            ]);
        }

        $rate = WebThreeService::getRate();

        $last = round(1 / ($usdt['last'] * $rate), 5);

        $where = [
            ['type','=', 0],
            ['base_ccy','=','SWT']
        ];

        $lastSz = SwtOrder::where($where) -> sum('price');

        $volCcy24h = SwtOrder::where($where) -> whereDate('created_at', today()) -> sum('price');

        $vol24h = SwtOrder::where($where) -> count();

        SwtMarketChains::where('inst_id','SWT-USD') -> update([
            "last"      => $last,
            "lastSz"    => round($lastSz, 5),
            "askPx"     => 5,
            "askSz"     => 0,
            "bidPx"     => 5,
            "bidSz"     => 0,
            "open24h"   => $last,
            "high24h"   => $last,
            "low24h"    => $last,
            "volCcy24h" => $volCcy24h,
            "vol24h"    => $vol24h,
            "sodUtc0"   => $last,
            "sodUtc8"   => $last,
        ]);

        return true;
    }

    /**
     * @notes 缓存K线数据
     * @param string $instId
     * @param string $bar
     * @param string $after
     * @param int $limit
     * @return bool
     * @author Evil丿
     * @date 2025/04/17 10:44
     */
    public static function getMarketCandles(string $instId, string $bar, string $after, int $limit) : array
    {
        if(!$after) {
            $after = round(microtime(true) * 1000);
        }

        $res = WebThreeService::getMarketCandles($instId, $bar, $after, $limit);

        if($res['code'] != 0) {
            self::$error = $res['msg'];
            return [];
        }

        return $res['data'];
    }

    /**
     * @notes 获取所有行情数据，并分页返回
     * @param string $quote_ccy
     * @param int $pageNo
     * @param int $pageSize
     * @return array
     * @author Evil丿
     * @date 2025/04/18 10:28
     */
    public static function getAllChains(string  $search = '', int $pageNo = 1, int $pageSize = 15) : array
    {
        $chains = SwtMarketChains::where('quote_ccy', 'USDT') -> where('state', 'live') -> orderBy('inst_id');

        if($search) {
            $chains -> where('inst_id','like','%'.$search.'%');
        }

        $pages = $chains -> paginate(
            perPage: $pageSize,
            columns: ['*'],
            pageName: 'pageNo',
            page: $pageNo
        );

        $list = $chains -> get() -> map(function ($item) {
            $item -> icon = config('app.url').'/storage'.$item -> icon;
            $item -> instId = $item -> inst_id;
            return $item;
        });
        return [
            'list'        => $list,
            'pageNo'      => $pages->currentPage(),
            'pageSize'    => $pages->perPage(),
            'count'       => $pages->total(),
            'noMore'      => !$pages->hasMorePages(),
        ];
    }

    /**
     * @notes 获取主流币种行情数据
     * @param string $quote_ccy
     * @return array
     * @author Evil丿
     * @date 2025/04/16 17:35
     */
    public static function getMainChains(string $search = "", int $pageNo = 1, int $pageSize = 15) : array
    {
        $chains = SwtMarketChains::where('quote_ccy', "USD") -> where('mark', 'main') -> where('state', 'live') -> orderBy('inst_id');

        if($search) {
            $chains -> where('inst_id','like','%'.$search.'%');
        }

        $pages = $chains -> paginate(
            perPage: $pageSize,
            columns: ['*'],
            pageName: 'pageNo',
            page: $pageNo
        );

        $list = $chains -> get() -> map(function ($item) {
            $item -> icon = config('app.url').'/storage'.$item -> icon;
            $item -> instId = $item -> inst_id;
            return $item;
        });

        return [
            'list'        => $list,
            'pageNo'      => $pages->currentPage(),
            'pageSize'    => $pages->perPage(),
            'count'       => $pages->total(),
            'noMore'      => !$pages->hasMorePages(),
        ];
    }

    /**
     * @notes 获取行情数据，按创建时间排序
     * @param string $quote_ccy
     * @param int $pageNo
     * @param int $pageSize
     * @return array
     * @author Evil丿
     * @date 2025/04/16 17:37
     */
    public static function getChainsByCreateTime(string  $search = '', int $pageNo = 1, int $pageSize = 15) : array
    {
        $chains = SwtMarketChains::where('quote_ccy', "USDT") -> where('state', 'live') -> orderBy('list_time','desc');

        if($search) {
            $chains -> where('inst_id','like','%'.$search.'%');
        }

        $pages = $chains -> paginate(
            perPage: $pageSize,
            columns: ['*'],
            pageName: 'pageNo',
            page: $pageNo
        );

        $list = $chains -> get() -> map(function ($item) {
            $item -> icon = config('app.url').'/storage'.$item -> icon;
            $item -> instId = $item -> inst_id;
            return $item;
        });

        return [
            'list'        => $list,
            'pageNo'      => $pages->currentPage(),
            'pageSize'    => $pages->perPage(),
            'count'       => $pages->total(),
            'noMore'      => !$pages->hasMorePages(),
        ];
    }

    /**
     * @notes 获取热门币种行情数据，按热度排序（24小时交易量）
     * @param string $quote_ccy
     * @param int $pageNo
     * @param int $pageSize
     * @return array
     * @author Evil丿
     * @date 2025/04/16 17:40
     */
    public static function getChainsByHeat(string  $search = '', int $pageNo = 1, int $pageSize = 15) : array
    {
        $chains = SwtMarketChains::where('quote_ccy', "USDT") -> where('state', 'live') -> orderBy('volCcy24h','desc');

        if($search) {
            $chains -> where('inst_id','like','%'.$search.'%');
        }

        $pages = $chains -> paginate(
            perPage: $pageSize,
            columns: ['*'],
            pageName: 'pageNo',
            page: $pageNo
        );

        $list = $chains -> get() -> map(function ($item) {
            $item -> icon = config('app.url').'/storage'.$item -> icon;
            $item -> instId = $item -> inst_id;
            return $item;
        });

        return [
            'list'        => $list,
            'pageNo'      => $pages->currentPage(),
            'pageSize'    => $pages->perPage(),
            'count'       => $pages->total(),
            'noMore'      => !$pages->hasMorePages(),
        ];
    }

    /**
     * @notes 获取涨幅排行，按涨幅排序
     * @param string $quote_ccy
     * @param int $pageNo
     * @param int $pageSize
     * @return array
     * @author Evil丿
     * @date 2025/04/16 17:42
     */
    public static function getChainsByInc(string  $search = '', int $pageNo = 1, int $pageSize = 15) : array
    {
        $chains = SwtMarketChains::select('*',DB::raw('(last - sodUtc8) / sodUtc8 as inc'))
            -> where('quote_ccy', "USDT")
            -> where('state', 'live')
            -> orderBy('inc','desc');

        if($search) {
            $chains -> where('inst_id','like','%'.$search.'%');
        }

        $pages = $chains -> paginate(
            perPage: $pageSize,
            columns: ['*'],
            pageName: 'pageNo',
            page: $pageNo
        );

        $list = $chains -> get() -> map(function ($item) {
            $item -> icon = config('app.url').'/storage'.$item -> icon;
            $item -> instId = $item -> inst_id;
            return $item;
        });

        return [
            'list'        => $list,
            'pageNo'      => $pages->currentPage(),
            'pageSize'    => $pages->perPage(),
            'count'       => $pages->total(),
            'noMore'      => !$pages->hasMorePages(),
        ];
    }

    /**
     * @notes 获取SWT行情数据
     * @return array
     * @author Evil丿
     * @date 2025/04/17 15:07
     */
    public static function getSwtChains() : array
    {
        $item = SwtMarketChains::where('inst_id','SWT-USD')->first();
        $item -> icon = config('app.url').'/storage'.$item -> icon;
        $item -> instId = $item -> inst_id;
        return $item -> toArray();
    }

    /**
     * @notes 增加提币订单
     * @param int $coin_id
     * @param int $network_id
     * @param string $to_address
     * @param string $num
     * @return bool|array
     * @author Evil丿
     * @date 2025/04/23 12:36
     */
    public static function addWithdrawOrder(int $coin_id, int $network_id, string $to_address, string $num, int $user_id) : bool|array
    {
        $res = SwtNetworkChain::where('network_id',$network_id) -> where('chain_id', $coin_id) -> doesntExist();

        if($res) {
            self::$error = __("coin-type.coin_not_found");
            return false;
        }

        $coin_info = SwtMarketChains::where('id', $coin_id) -> first();

        if(!$coin_info) {
            self::$error = __("coin-type.coin_not_found");
            return false;
        }

        $network_info = SwtNetwork::where('id', $network_id) -> first();

        if(!$network_info) {
            self::$error = __("coin-type.network_not_found");
            return false;
        }

        $account_id = SwtTradeAccount::where('user_id', $user_id) -> where('type',1) -> value('id');

        if(!$account_id) {
            self::$error = __("coin-type.account_not_found");
            return false;
        }

        $address = SwtTradeAddress::where('account_id', $account_id) -> where('chain_name', $coin_info -> base_ccy) -> first();

        if(!$address) {
            self::$error = __("coin-type.address_not_found");
            return false;
        }

        if($address -> total < $num) {
            self::$error = __("coin-type.funding_insufficient_balance");
            return false;
        }

        $data = [
            "address_id" => $address->id,
            "user_id"    => $user_id,
            "coin_id"    => $coin_id,
            "network_id" => $network_id,
            "to_address" => $to_address,
            "type"       => 1,
            "num"        => $num
        ];

        $res = SwtTradeOrder::create($data);

        if(!$res) {
            self::$error = __("order.order_create_fail");
            return false;
        }

        $address -> total -= $num;
        $address -> save();

        return true;
    }
}
